import streamlit as st
import pandas as pd
import os
#import matplotlib.pyplot as plt
from pandasql import sqldf

import Config
Config.main()


##################
# 页面设置
st.set_page_config(page_title="数据预览", page_icon="📊")
st.header("数据预览")
st.markdown("* 预览数据")
st.markdown("* 修改文件头")
st.write("*"*10)


##################
# 选项窗口
st.session_state.P01_datafile_info = st.text_input("请输入数据文件夹路径，或者数据文件路径：", value=st.session_state.P01_datafile_info)
if os.path.exists(st.session_state.P01_datafile_info) and os.path.isfile(st.session_state.P01_datafile_info):    
    datafile_path = st.session_state.P01_datafile_info
elif os.path.exists(st.session_state.P01_datafile_info):
    st.session_state.P01_datafile_name = st.selectbox("请选择数据文件：", options=os.listdir(st.session_state.P01_datafile_info))
    datafile_path = os.path.join(st.session_state.P01_datafile_info, st.session_state.P01_datafile_name)
else:
    datafile_path = None
    st.error("请输入正确的数据文件信息")

st.session_state.P01_seperator = st.text_input("数据文件分隔符：", value=st.session_state.P01_seperator)
st.session_state.P01_encoding = st.text_input("数据文件编码：", value=st.session_state.P01_encoding)
st.session_state.P01_preview_rows = int(st.text_input("预览数据行数：", value=st.session_state.P01_preview_rows))
st.session_state.P01_firstline = st.checkbox("第一行是头信息，非数据", value=st.session_state.P01_firstline)

st.session_state.P01_headfile_info = st.text_input("请输入头文件路径，或者输入表头字符串，或者留空：", value=st.session_state.P01_headfile_info)
if st.session_state.P01_headfile_info is None or len(st.session_state.P01_headfile_info)==0:
    st.warning("未引入头文件，程序将认定数据文件自带头信息")
    headfile_info = None
elif(os.path.exists(st.session_state.P01_headfile_info)):
    st.session_state.P01_headfile_name = st.selectbox("请选择头文件【xlsx文件】：", options=os.listdir(st.session_state.P01_headfile_info))
    pass # 调用函数，读取头文件信息
    df = pd.read_excel(os.path.join(st.session_state.P01_headfile_info, st.session_state.P01_headfile_name))
    headfile_info = df.iloc[:,0].tolist()
    del df
    st.warning(f"使用文件 {st.session_state.P01_headfile_name} 作为头文件，头信息为 {headfile_info}")
else:
    #对字符串进行清洗，作为头信息
    st.session_state.P01_headfile_info = st.session_state.P01_headfile_info.replace('，', ',').replace('\t', ',').replace(' ', ',')
    headfile_info = st.session_state.P01_headfile_info.split(',')
    st.warning(f"头信息为 {headfile_info}")
st.write("*"*10)

##################
# 显示文件信息
st.write(f"当前文件夹路径： {st.session_state.P01_datafile_info}")
if datafile_path is not None:
    st.write(f"数据文件路径： {datafile_path}")
    st.write(f"数据文件大小： {round(os.path.getsize(datafile_path)/1024, 2)}KB / {round(os.path.getsize(datafile_path)/1024/1024, 2)}MB / {round(os.path.getsize(datafile_path)/1024/1024/1024, 2)}GB")


#########################################################################################
##################
# 读取文件并预览
# 1. csv文件有表头并且是第一行，那么names和header都无需指定;
# 2. csv文件有表头、但表头不是第一行，可能从下面几行开始才是真正的表头和数据，这个时候指定header即可;
# 3. csv文件没有表头，全部是纯数据，那么我们可以通过names手动生成表头;
# 4. csv文件有表头、但是这个表头你不想用，这个时候同时指定names和header。先用header选出表头和数据，
#    然后再用names将表头替换掉，就等价于将数据读取进来之后再对列名进行rename；
df = None
names = headfile_info #默认值为None
header = 0 #默认值为infer
if st.session_state.P01_firstline:
    header = 0
else:
    header = None
nrows = st.session_state.P01_preview_rows
sep = st.session_state.P01_seperator
encoding = st.session_state.P01_encoding
if st.button("预览数据"):
    df = pd.read_csv(datafile_path, names=names, header=header, nrows=nrows, sep=sep, encoding=encoding)
    if df is None:
        st.write("文件读取失败")
    st.dataframe(df)
    del df



def modify_file_head(filepath, headinfo, mode='modify'):
    # 增加文件名后缀 '_modified'
    input_file_path = filepath
    input_file_dir, input_file_name = os.path.split(input_file_path)
    input_file_base, input_file_ext = os.path.splitext(input_file_name)
    output_file_name = f"{input_file_base}_modified{input_file_ext}"
    output_file_path = os.path.join(input_file_dir, output_file_name)

    # 打开输入文件和输出文件
    with open(input_file_path, "r") as input_file, open(output_file_path, "w") as output_file:
        # 将头文件信息写入第一行
        output_file.write(headinfo+"\n")
        # 逐行读取文件内容
        for index, line in enumerate(input_file):
            if mode == 'modify' and index==0:
                # 该模式下，丢掉第一行内容
                continue
            # 对每一行进行处理，例如替换特定字符串
            #new_line = line.replace("old_string", "new_string")
            # 将处理后的内容写入输出文件
            output_file.write(line)
    return output_file_path


if st.button("修改数据文件，增加表头信息"):
    if headfile_info is None:
        st.warning("没有头文件信息，未修改")
    else:
        headinfo = sep.join(headfile_info)
        if header==0:
            output_file_path = modify_file_head(datafile_path, headinfo, mode='modify')
        else:
            output_file_path = modify_file_head(datafile_path, headinfo, mode='insert')
        st.success(f"表头信息已增加： {output_file_path}")


##########################################################
st.write("---")

st.write("更快的读写速度：HDF5文件采用二进制格式存储数据，相比于CSV文件的文本格式，读写速度更快，尤其是对于大型数据集。")
#import h5py
def csv2h5(csv_file, sep, chunk_size, name):
    input_file_path = csv_file
    input_file_dir, input_file_name = os.path.split(input_file_path)
    input_file_base, input_file_ext = os.path.splitext(input_file_name)
    output_file_name = f"{input_file_base}_convert.h5"
    output_file_path = os.path.join(input_file_dir, output_file_name)
    
    df_chunks = pd.read_csv(csv_file,
                            sep=sep,
                            index_col=0,
                            chunksize=chunk_size)

    with h5py.File(output_file_path, 'w') as file:
        total_cols = 0
        for i, chunk in enumerate(df_chunks):
            chunk = chunk.transpose()
            chunk = chunk.fillna(0)
            # 0填充
            data_array = chunk.to_numpy()
            chunk_cols = data_array.shape[1]
            if i == 0:
                samples_num = data_array.shape[0]
                dataset = file.create_dataset('data',
                                              shape=data_array.shape,
                                              maxshape=(samples_num, None))

            dataset.resize((dataset.shape[0], total_cols + chunk_cols))

            dataset[:, total_cols:total_cols + chunk_cols] = data_array

            total_cols += chunk_cols
    return output_file_path
if st.button("转换为HDF5文件"):
    output_file_path = csv2h5(datafile_path , 5000)
    st.success(f"数据文件已转换为HDF5： {output_file_path}")